/**
 * 对话控制器
 * 处理对话相关的业务逻辑
 */
const asyncHandler = require('express-async-handler');
const Conversation = require('../models/conversation');
const Message = require('../models/message');
const User = require('../models/user');

/**
 * 获取用户的所有对话
 * @route GET /api/conversations
 * @access Private
 */
const getConversations = asyncHandler(async (req, res) => {
  // 查找用户参与的所有对话
  const conversations = await Conversation.find({
    participants: { $in: [req.user._id] }
  })
    .populate('participants', 'username avatar isOnline lastSeen')
    .populate({
      path: 'latestMessage',
      select: 'content createdAt sender readBy',
      populate: {
        path: 'sender',
        select: 'username avatar'
      }
    })
    .sort({ updatedAt: -1 });

  res.json(conversations);
});

/**
 * 获取特定对话
 * @route GET /api/conversations/:conversationId
 * @access Private
 */
const getConversationById = asyncHandler(async (req, res) => {
  const conversation = await Conversation.findById(req.params.conversationId)
    .populate('participants', 'username avatar isOnline lastSeen bio')
    .populate({
      path: 'latestMessage',
      select: 'content createdAt sender readBy',
      populate: {
        path: 'sender',
        select: 'username avatar'
      }
    });

  // 检查对话是否存在
  if (!conversation) {
    res.status(404);
    throw new Error('对话未找到');
  }

  // 检查用户是否为对话参与者
  if (!conversation.participants.some(p => p._id.toString() === req.user._id.toString())) {
    res.status(403);
    throw new Error('无权访问此对话');
  }

  res.json(conversation);
});

/**
 * 获取对话中的消息
 * @route GET /api/conversations/:conversationId/messages
 * @access Private
 */
const getConversationMessages = asyncHandler(async (req, res) => {
  const conversation = await Conversation.findById(req.params.conversationId);

  // 检查对话是否存在
  if (!conversation) {
    res.status(404);
    throw new Error('对话未找到');
  }

  // 检查用户是否为对话参与者
  if (!conversation.participants.includes(req.user._id)) {
    res.status(403);
    throw new Error('无权访问此对话');
  }

  const page = parseInt(req.query.page) || 1;
  const limit = parseInt(req.query.limit) || 20;
  const skip = (page - 1) * limit;

  // 获取对话中的消息
  const messages = await Message.find({ conversation: req.params.conversationId })
    .populate('sender', 'username avatar')
    .sort({ createdAt: -1 })
    .skip(skip)
    .limit(limit);

  // 获取总消息数
  const totalMessages = await Message.countDocuments({ conversation: req.params.conversationId });

  res.json({
    messages: messages.reverse(),
    pagination: {
      page,
      limit,
      totalMessages,
      totalPages: Math.ceil(totalMessages / limit)
    }
  });
});

/**
 * 标记对话为已读
 * @route PUT /api/conversations/:conversationId/read
 * @access Private
 */
const markConversationAsRead = asyncHandler(async (req, res) => {
  const conversation = await Conversation.findById(req.params.conversationId);

  // 检查对话是否存在
  if (!conversation) {
    res.status(404);
    throw new Error('对话未找到');
  }

  // 检查用户是否为对话参与者
  if (!conversation.participants.includes(req.user._id)) {
    res.status(403);
    throw new Error('无权访问此对话');
  }

  // 标记所有未读消息为已读
  await Message.updateMany(
    {
      conversation: req.params.conversationId,
      sender: { $ne: req.user._id },
      readBy: { $ne: req.user._id }
    },
    {
      $addToSet: { readBy: req.user._id }
    }
  );

  res.json({ message: '对话已标记为已读' });
});

/**
 * 删除对话
 * @route DELETE /api/conversations/:conversationId
 * @access Private
 */
const deleteConversation = asyncHandler(async (req, res) => {
  const conversation = await Conversation.findById(req.params.conversationId);

  // 检查对话是否存在
  if (!conversation) {
    res.status(404);
    throw new Error('对话未找到');
  }

  // 检查用户是否为对话参与者
  if (!conversation.participants.includes(req.user._id)) {
    res.status(403);
    throw new Error('无权访问此对话');
  }

  // 删除对话相关的所有消息
  await Message.deleteMany({ conversation: req.params.conversationId });

  // 删除对话
  await conversation.remove();

  res.json({ message: '对话已删除' });
});

module.exports = {
  getConversations,
  getConversationById,
  getConversationMessages,
  markConversationAsRead,
  deleteConversation
}; 